﻿
// Various tests for the:
// Microsoft.FSharp.Core.LanguagePrimitives module

namespace FSharp.Core.Unittests.FSharp_Core.Microsoft_FSharp_Core

open System
open System.Numerics 
open FSharp.Core.Unittests.LibraryTestFx
open NUnit.Framework

[<Measure>]
type m

[<TestFixture>]
type LanguagePrimitivesModule() =
    [<Test>]
    member this.CastingUnits() =
        let f = 2.5
        let ff= 2.5f
        let d = 2.0m
        let i = 2
        let l = 2L
        let s = 2s
        let y = 2y
        Assert.AreEqual(f, f |> LanguagePrimitives.FloatWithMeasure<m> |> float)
        Assert.AreEqual(ff, ff |> LanguagePrimitives.Float32WithMeasure<m> |> float32)
        Assert.AreEqual(d, d |> LanguagePrimitives.DecimalWithMeasure<m> |> decimal)
        Assert.AreEqual(i, i |> LanguagePrimitives.Int32WithMeasure<m> |> int)
        Assert.AreEqual(l, l |> LanguagePrimitives.Int64WithMeasure<m> |> int64)
        Assert.AreEqual(s, s |> LanguagePrimitives.Int16WithMeasure<m> |> int16)
        Assert.AreEqual(y, y |> LanguagePrimitives.SByteWithMeasure<m> |> sbyte)

    [<Test>]
    member this.DivideByInt() =
            
        // float32 
        let resultFloat32 = LanguagePrimitives.DivideByInt 3.0f 3
        Assert.AreEqual(resultFloat32, 1.0f)
        
        // double 
        let resultDouble = LanguagePrimitives.DivideByInt 3.9 3
        Assert.AreEqual(resultDouble,1.3)
        
        // decimal 
        let resultDecimal = LanguagePrimitives.DivideByInt 3.9M 3
        Assert.AreEqual(resultDecimal,1.3M)   
        
        
        ()

    [<Test>]
    member this.EnumOfValue() =  
        let monday = System.DayOfWeek.Monday
        let result = LanguagePrimitives.EnumOfValue<int,System.DayOfWeek>(1)
        
        Assert.AreEqual(result,monday)
        
        ()
    
    [<Test>]
    member this.EnumToValue() =

        let monday = System.DayOfWeek.Monday
        let result = LanguagePrimitives.EnumToValue monday
        Assert.AreEqual(result,1)
        
        ()   
        
    [<Test>]
    member this.GuidToString() =
        let s = "F99D95E0-2A5E-47c4-9B92-6661D65AE6B3"
        let guid = new Guid(s)
        Assert.AreEqual(s.ToLower(Globalization.CultureInfo.InvariantCulture), (string guid).ToLower(Globalization.CultureInfo.InvariantCulture))

    [<Test>]
    member this.GenericComparison() =

        // value type
        let resultValue = LanguagePrimitives.GenericComparison 1 1
        Assert.AreEqual(resultValue,0)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericComparison "ABC" "ABCDE"
        Assert.AreEqual(resultRef,-68)
        
        // null reference
        let resultRef = LanguagePrimitives.GenericComparison "ABC" null
        Assert.AreEqual(resultRef,1)
        
        ()   


#if SILVERLIGHT
#else    
    [<Test>]
    member this.GenericComparisonBiModal() =

        // value type
        let resultValue = LanguagePrimitives.GenericComparisonWithComparer System.Collections.Comparer.Default 1 1
        Assert.AreEqual(resultValue,0)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericComparisonWithComparer System.Collections.Comparer.Default "ABC" "ABCDE"
        Assert.AreEqual(resultRef,-68)
        
        // null reference
        let resultRef = LanguagePrimitives.GenericComparisonWithComparer System.Collections.Comparer.Default "ABC" null
        Assert.AreEqual(resultRef,1)
        
        ()   
#endif
        
    [<Test>]
    member this.GenericEquality() =

        // value type
        let resultValue = LanguagePrimitives.GenericEquality 1 1
        Assert.IsTrue(resultValue)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericEquality "ABC" "ABCDE"
        Assert.IsFalse(resultRef)
        
        // null reference
        let resultNul = LanguagePrimitives.GenericEquality null null
        Assert.IsTrue(resultNul)
        
        ()
        
    [<Test>]
    member this.GenericGreaterOrEqual() =

        // value type
        let resultValue = LanguagePrimitives.GenericGreaterOrEqual 1 1
        Assert.IsTrue(resultValue)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericEquality "ABC" "ABCDE"
        Assert.IsFalse(resultRef)
        
        // null reference
        let resultNul = LanguagePrimitives.GenericEquality null null
        Assert.IsTrue(resultNul)
        
        ()
        
        
    [<Test>]
    member this.GenericGreaterThan() =

        // value type
        let resultValue = LanguagePrimitives.GenericGreaterThan 1 1
        Assert.IsFalse(resultValue)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericGreaterThan "ABC" "ABCDE"
        Assert.IsFalse(resultRef)
        
        // null reference
        let resultNul = LanguagePrimitives.GenericGreaterThan null null
        Assert.IsFalse(resultNul)
        
        ()
        
        
    [<Test>]
    member this.GenericHash() =

        // value type
        let resultValue = LanguagePrimitives.GenericHash 1 
        Assert.AreEqual(1, resultValue)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericHash "ABC" 
        Assert.AreEqual("ABC".GetHashCode(), resultRef)
        
        // null reference
        let resultNul = LanguagePrimitives.GenericHash null 
        Assert.AreEqual(0, resultNul)
        
        ()   
        
        
    [<Test>]
    member this.GenericLessOrEqual() =

        // value type
        let resultValue = LanguagePrimitives.GenericLessOrEqual 1 1
        Assert.IsTrue(resultValue)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericLessOrEqual "ABC" "ABCDE"
        Assert.IsTrue(resultRef)
        
        // null reference
        let resultNul = LanguagePrimitives.GenericLessOrEqual null null
        Assert.IsTrue(resultNul)
        
        ()
        
        
    [<Test>]
    member this.GenericLessThan() =

        // value type
        let resultValue = LanguagePrimitives.GenericLessThan 1 1
        Assert.AreEqual(resultValue,false)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericLessThan "ABC" "ABCDE"
        Assert.AreEqual(resultRef,true)
        
        // null reference
        let resultNul = LanguagePrimitives.GenericLessThan null null
        Assert.AreEqual(resultNul,false)
        
        ()

    [<Test>]
    member this.GenericMaximum() =

        // value type
        let resultValue = LanguagePrimitives.GenericMaximum 8 9
        Assert.AreEqual(resultValue,9)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericMaximum "ABC" "ABCDE"
        Assert.AreEqual(resultRef,"ABCDE")
        
        // null reference
        let resultNul = LanguagePrimitives.GenericMaximum null null
        Assert.AreEqual(resultNul,null)
        
        ()
        
    [<Test>]
    member this.GenericMinimum() =

        // value type
        let resultValue = LanguagePrimitives.GenericMinimum 8 9
        Assert.AreEqual(resultValue,8)
        
        // reference type
        let resultRef = LanguagePrimitives.GenericMinimum "ABC" "ABCDE"
        Assert.AreEqual(resultRef,"ABC")
        
        // null reference
        let resultNul = LanguagePrimitives.GenericMinimum null null
        Assert.AreEqual(resultNul,null)
        
        ()
        
    [<Test>]
    member this.GenericOne() =

        // bigint type
        let resultValue = LanguagePrimitives.GenericOne<bigint> 
        Assert.AreEqual(resultValue,1I)
        
        ()
        
    [<Test>]
    member this.GenericZero() =

        // bigint type
        let resultValue = LanguagePrimitives.GenericZero<bigint> 
        Assert.AreEqual(resultValue,0I)
        
        ()
        
    [<Test>]
    member this.ParseInt32() =
        
        let resultValue = LanguagePrimitives.ParseInt32 "100" 
        Assert.AreEqual(resultValue,100)    
        
        CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseInt32 null  |> ignore)
        
        ()
        
    [<Test>]
    member this.ParseInt64() =
        
        let resultValue = LanguagePrimitives.ParseInt64 "100" 
        Assert.AreEqual(resultValue,100L)    
        
        CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseInt64 null  |> ignore)
        
        ()
        
    [<Test>]
    member this.ParseUInt32() =
        
        let resultValue = LanguagePrimitives.ParseUInt32 "100" 
        Assert.AreEqual(resultValue,100ul)        
        
        
        CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseUInt32 null  |> ignore)
        
        ()
        
    [<Test>]
    member this.ParseUInt64() =
        
        let resultValue = LanguagePrimitives.ParseUInt64 "100" 
        Assert.AreEqual(resultValue,100UL)        
        
        CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseUInt64 null  |> ignore)
        
        ()

    [<Test>]
    member this.ParseStringViaConversionOps() =
        let s : string = null
        CheckThrowsArgumentNullException2 "sbyte" (fun () -> sbyte s |> ignore)
        CheckThrowsArgumentNullException2 "byte" (fun () -> byte s |> ignore)
        CheckThrowsArgumentNullException2 "int16" (fun () -> int16 s |> ignore)
        CheckThrowsArgumentNullException2 "uint16 " (fun () -> uint16 s |> ignore)
        CheckThrowsArgumentNullException2 "int" (fun () -> int s |> ignore)
        CheckThrowsArgumentNullException2 "int32" (fun () -> int32 s |> ignore)
        CheckThrowsArgumentNullException2 "uint32" (fun () -> uint32 s |> ignore)
        CheckThrowsArgumentNullException2  "int64" (fun () -> int64 s |> ignore)
        CheckThrowsArgumentNullException2 "uint64" (fun () -> uint64 s |> ignore)
        CheckThrowsArgumentNullException2 "float32" (fun () -> float32 s |> ignore)
        CheckThrowsArgumentNullException2 "float" (fun () -> float s |> ignore)
        CheckThrowsArgumentNullException2 "decimal" (fun () -> decimal s |> ignore)
        CheckThrowsArgumentNullException2 "char" (fun () -> char s |> ignore)
        
    [<Test>]
    member this.PhysicalEquality() =

        // revordtype
        let ref1 = ref 8
        let ref2 = ref 8
        let resultValue = LanguagePrimitives.PhysicalEquality ref1 ref2
        Assert.IsFalse(resultValue)
        Assert.IsTrue(LanguagePrimitives.PhysicalEquality ref1 ref1)
        Assert.IsTrue(LanguagePrimitives.PhysicalEquality ref2 ref2)
        
        // reference type
        let resultRef0 = LanguagePrimitives.PhysicalEquality "ABC" "ABC"
        Assert.IsTrue(resultRef0)
        
        let resultRef1 = LanguagePrimitives.PhysicalEquality "ABC" "DEF"
        Assert.IsFalse(resultRef1)
        
        // object type
        let resultRef2 = LanguagePrimitives.PhysicalEquality (obj()) (obj())
        Assert.IsFalse(resultRef2)
        
        // object type
        let o = obj()
        let resultRef3 = LanguagePrimitives.PhysicalEquality o o 
        Assert.IsTrue(resultRef3)
        
        // System.ValueType type
        let resultRef4 = LanguagePrimitives.PhysicalEquality (1 :> System.ValueType) (1 :> System.ValueType)
        Assert.IsFalse(resultRef4)
        
        // System.ValueType type
        let resultRef5 = LanguagePrimitives.PhysicalEquality (1 :> System.ValueType) (2 :> System.ValueType)
        Assert.IsFalse(resultRef5)
        
        // null reference
        let resultNul = LanguagePrimitives.PhysicalEquality null null
        Assert.IsTrue(resultNul)

[<TestFixture>]
type HashCompareModule() = // this module is internal/obsolete, but contains code reachable from many public APIs
    member inline this.ComparisonsFor< ^T when ^T : comparison>(x : ^T, y : ^T) =
        Assert.IsTrue( x < y )
        Assert.IsTrue( y > x ) 
        Assert.IsTrue( (x = x) )
        Assert.IsFalse( y < x )
        Assert.IsFalse( x > y )
        Assert.IsFalse( (x = y) )
        ()     
    [<Test>]
    member this.ComparisonsForArraysOfNativeInts() =
        this.ComparisonsFor( [|0n|], [|1n|] )
        this.ComparisonsFor( [|0un|], [|1un|] )
        ()     
    [<Test>]
    member this.ComparisonsForArraysOfFloatingPoints() =
        this.ComparisonsFor( [|0.0|], [|1.0|] )
        this.ComparisonsFor( [|0.0f|], [|1.0f|] )
        Assert.IsFalse( [| System.Double.NaN |] = [| System.Double.NaN |] )
        Assert.IsFalse( [| System.Single.NaN |] = [| System.Single.NaN |] )
        Assert.IsFalse( [| System.Double.NaN |] < [| System.Double.NaN |] )
        Assert.IsFalse( [| System.Single.NaN |] < [| System.Single.NaN |] )
        ()     
    [<Test>]
    member this.ComparisonsForOtherArrays() =
        this.ComparisonsFor( [|0uy|], [|1uy|] )
        this.ComparisonsFor( [|'a'|], [|'b'|] )
        this.ComparisonsFor( [|0UL|], [|1UL|] )
    [<Test>]
    member this.ComparisonsForStrings() =
        this.ComparisonsFor( "bar", "foo" )
        this.ComparisonsFor( [| "bar" |], [| "foo" |] )
    [<Test>]
    member this.ComparisonsForMultidimensionalIntArrays() =
        let N = 10
        let M = 100
        let Z = 9999
        let x = Array2D.init 3 3 (fun x y -> N*x + y)
        let y = Array2D.init 3 3 (fun x y -> N*x + y)
        Assert.IsTrue( hash x = hash y )
        y.[2,2] <- Z
        this.ComparisonsFor( x, y )
        let x = Array3D.init 3 3 3 (fun x y z -> M*x + N*y + z)
        let y = Array3D.init 3 3 3 (fun x y z -> M*x + N*y + z)
        Assert.IsTrue( hash x = hash y )
        y.[2,2,2] <- Z
        this.ComparisonsFor( x, y )
    [<Test>]
    member this.ComparisonsForMultidimensionalInt64Arrays() =
        let N = 10L
        let M = 100L
        let Z = 9999L
        let x = Array2D.init 3 3 (fun x y -> N*(int64 x) + (int64 y))
        let y = Array2D.init 3 3 (fun x y -> N*(int64 x) + (int64 y))
        Assert.IsTrue( hash x = hash y )
        y.[2,2] <- Z
        this.ComparisonsFor( x, y )
        let x = Array3D.init 3 3 3 (fun x y z -> M*(int64 x) + N*(int64 y) + (int64 z))
        let y = Array3D.init 3 3 3 (fun x y z -> M*(int64 x) + N*(int64 y) + (int64 z))
        Assert.IsTrue( hash x = hash y )
        y.[2,2,2] <- Z
        this.ComparisonsFor( x, y )
    
    [<Test>]
    member this.MonsterTuple() =
        let mt = 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
        let mt2 = 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
        Assert.AreEqual(mt,mt2)
        
[<TestFixture>]
type IntrinsicFunctionsModule() =
    [<Test>]
    member this.Obsolete() =
        // all method obsoleted and inlined        
        ()     
    

[<TestFixture>]
type IntrinsicOperatorsModule() =
    [<Test>]
    member this.Obsolete() =
        // all method obsoleted and inlined        
        ()  
    
[<TestFixture>]
type UnitType() =
    // interface
    [<Test>]
    member this.IComparable() =        
        let u:Unit = ()
        // value type
        let ic = u :> IComparable   
        CheckThrowsNullRefException(fun() ->ic.CompareTo(3) |>ignore) 
                
        ()
        
    // Base class methods
    [<Test>]
    member this.ObjectGetHashCode() =
        let u:Unit = ()
        CheckThrowsNullRefException(fun() ->u.GetHashCode() |>ignore) 
        
        ()
        
    [<Test>]
    member this.ObjectEquals() =
        let u:Unit = ()
        CheckThrowsNullRefException(fun() ->u.Equals(null) |>ignore) 
        
#if SILVERLIGHT
#else        
[<TestFixture>]
type SourceConstructFlagsEnum() =
    [<Test>]
    member this.Getvalue() =
        Assert.AreEqual(SourceConstructFlags.GetNames(typeof<SourceConstructFlags>),
                        [|"None";"SumType";"RecordType";"ObjectType";"Field";
                          "Exception";"Closure";"Module";"UnionCase";"Value";
                          "KindMask";"NonPublicRepresentation"|])
              
        ()
        
[<TestFixture>]
type CompilationRepresentationFlagsEnum() =
    [<Test>]
    member this.Getvalue() =
        Assert.AreEqual(SourceConstructFlags.GetNames(typeof<CompilationRepresentationFlags>),
                        [|"None";"Static";"Instance";"ModuleSuffix";"UseNullAsTrueValue";"Event"|])
            
        ()
#endif

[<TestFixture>]
type MiscStuff() =
    [<Test>]
    member this.ListToString() =
        Assert.IsTrue( [].ToString() = "[]" )
        Assert.IsTrue( [1].ToString() = "[1]" )
        Assert.IsTrue( [1;2].ToString() = "[1; 2]" )
        Assert.IsTrue( [1;2;3].ToString() = "[1; 2; 3]" )
        Assert.IsTrue( [1;2;3;4].ToString() = "[1; 2; 3; ... ]" )
    [<Test>]
    member this.Refs() =
        let x = ref 0
        incr x
        incr x
        decr x
        Assert.IsTrue( 1 = !x )
        
        
     
     
